import datetime
import numpy

from absl import flags

from coin.base.book.types import TradeSide

# pip install PyQt5
from PyQt5.QtWidgets import QHeaderView, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget
from PyQt5.QtGui import QColor, QFont, QPalette
from PyQt5.QtCore import Qt


def set_palette(app):
  palette = QPalette()
  palette.setColor(QPalette.Window, QColor(53, 53, 53))
  palette.setColor(QPalette.WindowText, Qt.white)
  palette.setColor(QPalette.Base, QColor(125, 125, 125))
  app.setPalette(palette)


class PyQtEngine(QWidget):
  def __init__(self, find_qty):
    super().__init__()
    self.title = ''
    self.left = 0
    self.top = 0
    self.width = 1260
    self.height = 980
    self.value = 0
    self.tableWidget = None
    self.die = False
    self.skip = 1
    self.last_skip = 1
    self.find_order = False
    self.init_find_qty = find_qty
    self.find_qty = None
    self.step = 1
    self.init_ui()
    self.buy_color = QColor(128, 255, 128)
    self.sell_color = QColor(255, 128, 128)
    self.buy_color_vivid = QColor(64, 255, 64)
    self.sell_color_vivid = QColor(255, 64, 64)
    self.buy_color_dark = QColor(192, 255, 192)
    self.sell_color_dark = QColor(255, 192, 192)
    self.during_key_change = False

  def set_title(self, title_input):
    self.title = title_input
    title = "[side: %s] (step: %s) %s" % (
        ("+" if self.step == 1 else "-"), self.last_skip, self.title)
    self.setWindowTitle(title)

  def init_ui(self):
    self.setGeometry(self.left, self.top, self.width, self.height)
    self.tableWidget = QTableWidget()
    self.tableWidget.setFont(QFont("monospace", 11))

    self.tableWidget.setFocusPolicy(Qt.NoFocus)
    self.tableWidget.horizontalHeader().setVisible(False)
    self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
    self.tableWidget.verticalHeader().setVisible(False)

    # Add box layout, add table to box layout and add box layout to widget
    self.layout = QVBoxLayout()
    self.layout.addWidget(self.tableWidget)
    self.setLayout(self.layout)
    # Show widget
    self.show()

  def update_table(self, df, trades, order_tpqs, self_pos, fills, symbol):
    self.value += 1

    self.tableWidget.setRowCount(df.values.shape[0] + 1)
    self.tableWidget.setColumnCount(df.values.shape[1] + 4)

    for j in range(df.values.shape[1]):
      self.tableWidget.setItem(0, j, QTableWidgetItem(df.columns[j]))

    try:
      tpqs = sorted(order_tpqs.values(), key=lambda tup: tup.price, reverse=True)
    except Exception:
      tpqs = sorted(order_tpqs, key=lambda tup: tup.price, reverse=True)
    tpqiter = 0

    prev_price = None
    curr_price = None

    for i in range(df.values.shape[0]):
      for j in range(df.values.shape[1]):
        text = df.values[i, j]
        if numpy.isnan(text):
          self.tableWidget.setItem(i + 1, j, QTableWidgetItem(str("")))
        else:
          self.tableWidget.setItem(i + 1, j, QTableWidgetItem(str(text)))
          self.tableWidget.item(i + 1,
                                j).setBackground(self.sell_color if j >= 2 else self.buy_color)
          if (j in [1, 3] and flags.FLAGS.large_qty is not None
              and df.values[i, j] > flags.FLAGS.large_qty):
            self.tableWidget.item(i + 1, j).setFont(QFont("monospace", 12, QFont.Bold))

      while tpqiter < len(tpqs):
        if numpy.isnan(df.values[i, 0]):
          curr_price = df.values[i, 2]
          priceloc = 0
          qtyloc = 1
        else:
          curr_price = df.values[i, 0]
          priceloc = 2
          qtyloc = 3

        if tpqs[tpqiter].sign > 0:
          incond = tpqs[tpqiter].price >= curr_price
        else:
          next_price = None if i + 1 == df.values.shape[0] else df.values[i + 1, 0]
          incond = (next_price is None) or tpqs[tpqiter].price > next_price

        if incond:
          tpq = tpqs[tpqiter]
          if tpq.qty > 0:
            self.tableWidget.setItem(i + 1, priceloc, QTableWidgetItem(str(tpq.price)))
            self.tableWidget.setItem(i + 1, qtyloc, QTableWidgetItem(str(tpq.qty * tpq.sign)))
            for col in [priceloc, qtyloc]:
              self.tableWidget.item(
                  i + 1,
                  col).setBackground(self.sell_color_dark if tpq.sign < 0 else self.buy_color_dark)
          tpqiter += 1
        else:
          break
      prev_price = curr_price

    self.tableWidget.setItem(1, 0, QTableWidgetItem(symbol))
    self.tableWidget.item(1, 0).setFont(QFont("monospace", 8, QFont.Bold))
    self.tableWidget.setItem(1, 1, QTableWidgetItem(str(self_pos)))

    for i, (timestamp, fill_price, fill_qty) in enumerate(fills[::-1]):
      ts_str = datetime.datetime.fromtimestamp(timestamp * 1e-9).strftime("%H:%M:%S.%f")
      # ts_str = pandas.DatetimeIndex([timestamp])[0].strftime("%H:%M:%S.%f")
      pq_str = "%7s@%.3f" % (fill_qty, fill_price)

      self.tableWidget.setItem(2 + i, 0, QTableWidgetItem(ts_str))
      self.tableWidget.setItem(2 + i, 1, QTableWidgetItem(pq_str))
      self.tableWidget.item(2 + i, 0).setFont(QFont("monospace", 10))
      self.tableWidget.item(2 + i, 1).setFont(QFont("monospace", 8))
      if fill_qty > 0:
        self.tableWidget.item(2 + i, 0).setBackground(self.buy_color_vivid)
        self.tableWidget.item(2 + i, 1).setBackground(self.buy_color_vivid)
      elif fill_qty < 0:
        self.tableWidget.item(2 + i, 0).setBackground(self.sell_color_vivid)
        self.tableWidget.item(2 + i, 1).setBackground(self.sell_color_vivid)

    if self_pos > 0:
      self.tableWidget.item(1, 0).setBackground(self.buy_color_vivid)
      self.tableWidget.item(1, 1).setBackground(self.buy_color_vivid)
    elif self_pos < 0:
      self.tableWidget.item(1, 0).setBackground(self.sell_color_vivid)
      self.tableWidget.item(1, 1).setBackground(self.sell_color_vivid)

    self.update_trade_table(trades)

  def update_trade_table(self, trades):
    assert len(trades) <= 30
    self.tableWidget.setItem(0, 4, QTableWidgetItem("time"))
    self.tableWidget.setItem(0, 5, QTableWidgetItem("side"))
    self.tableWidget.setItem(0, 6, QTableWidgetItem("price"))
    self.tableWidget.setItem(0, 7, QTableWidgetItem("qty"))
    for i, trade in enumerate(trades):
      if trade.side == TradeSide.TRADE_BUY_SIDE:
        sidestr = "BUY"
        color = self.buy_color
      else:
        sidestr = "SELL"
        color = self.sell_color

      dstr = datetime.datetime.fromtimestamp(trade.timestamp * 1e-9).strftime("%H:%M:%S.%f")
      # dstr = pandas.DatetimeIndex([trade.timestamp])[0].strftime("%H:%M:%S.%f")
      self.tableWidget.setItem(i + 1, 4, QTableWidgetItem(dstr))
      self.tableWidget.setItem(i + 1, 5, QTableWidgetItem(sidestr))
      self.tableWidget.setItem(i + 1, 6, QTableWidgetItem(str(round(trade.price, 5))))
      self.tableWidget.setItem(i + 1, 7, QTableWidgetItem(str(trade.qty)))
      for j in range(4, 8):
        self.tableWidget.item(i + 1, j).setBackground(color)

    # self.tableWidget.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
    # self.tableWidget.resizeColumnsToContents()
    # self.tableWidget.resizeRowsToContents()

  def keyPressEvent(self, event):
    if self.during_key_change:
      return
    self.during_key_change = True
    if event.key() == Qt.Key_Escape:
      self.die = True
      self.close()

    if event.key() == Qt.Key_Asterisk:
      self.last_skip *= 2
      self.set_title(self.title)

    if event.key() == Qt.Key_Slash:
      if abs(self.last_skip) > 1:
        self.last_skip = int(self.last_skip / 2)
        self.set_title(self.title)

    if event.key() == Qt.Key_Minus:
      self.step *= -1
      self.set_title(self.title)

    if event.key() == Qt.Key_Right:
      self.step = 1
      self.skip = self.last_skip

    if event.key() == Qt.Key_Left:
      self.step = -1
      self.skip = self.last_skip

    if event.key() == 78:  # 'n':
      self.step = 1
      self.find_order = True

    if event.key() == 80:  # 'p':
      self.step = -1
      self.find_order = True

    if event.key() == 70:  # 'f'
      self.step = 1
      self.find_qty = self.init_find_qty
      self.set_title('f')

    if event.key() == 68:  # 'd'
      self.step = -1
      self.find_qty = self.init_find_qty
      self.set_title('d')

    if 1 <= (event.key() - 48) <= 9:
      self.skip = 2**(event.key() - 48 - 1)
      self.last_skip = self.skip
      self.skip = 0
      self.set_title(self.title)
    self.during_key_change = False
